
/*
 * This pool consist of three parts.
 * 1,executed queue (thread);
 * 2,task queue (task);
 * 2,management tool;
 *
 * why I do not use array,because its size is fixed.
 *
 */

#include <iostream>
#include <pthread>

//insert a node
#define LL_ADD(item,list) do{                \
    item->prev = NULL;                       \
    item->next = list;                       \
    if(list != NULL) list->prev = item;      \
    list = item;                             \
}while(0)

//remove a node
#define LLREMOVE(item,list) do {                            \
    if(item->prev != NULL) item->prev->next = item->next;   \
    if(item->next != NULL) item->next->prev = item->prev;   \
    if(list == item) list = item->next;                     \
    item->prev = item->next = NULL;                         \
} while(0)

typedef struct NMANAGER nThreadPool;

static void* nThreadCallBack(void* arg){
    
    struct NWORKER* worker = (struct NWORKER*)arg;
    // status 1 runing 2 waiting
    while (1) {
        while (worker->pool->jobs == NULL) {
            if (worker->terminate) {
                break;
            }
            pthread_cond_wait(&worker->pool->jobs_cond,&worker->pool->jobs_mutex);
        }
        
        if (worker->terminate) {
            pthread_mutex_unlock(&worker->pool->jobs_mutex);
            break;
        }
        
        struct NJOB* job = worker->pool->jobs;
        LLREMOVE(job,worker->pool->jobs);
        pthread_mutex_unlock(&worker->pool->jobs_mutex);
        job->func(job-user_data);
    }
    free(worker);
    pthread_exit(NULL);
    pthread_cancel();
    
}

int nThreadPoolCreate(nThreadPool* pool,int numWorkers){
    
    if (numWorkers < 1) {
        numWorkers = 1;
    }
    
    if (pool == NULL) {
        return -1;
    }
    memset(pool,0,sizeof(nThreadPool));
    
    pthread_cond_t blank_cond = PTHREAD_COND_INITIALIZER;
    memcpy(&pool->jobs_cond,&blank_cond,sizeof(pthread_cond_t));
    pthread_mutex_t blank_mutex = PTHREAD_MUTEX_INITIALIZER;
    memcpy(&pool->jobs_mutex,&blank_mutex,sizeof(pthread_mutex_t));
    
    int i = 0;
    for (i = 0; i<numWorkers; i++) {
        struct  NWORKER* worker = (struct NWORKER*)malloc(sizeof(struct NWORKER));
        if (worker == NULL) {
            perror("malloc");
            return -2;
        }
        memset(worker,0,sizeof(struct NWORKER));
        worker->pool = pool;
        
        int ret = pthread_create(worker->thread,NULL,nThreadCallBack,worker);
        if (ret) {
            perror("pthread_create");
            return -3;
        }
        LL_ADD(worker,pool->workers);
    }
    
    
}


struct NWORKER{
    pthread_t thread;
    struct NWORKER *prev;
    struct NWORKER *next;
};

struct NJOB{
    void (*func)(struct NJOB *job);
    void *user_data;
    
    struct NJOB *prev;
    struct NJOB *next;
};

struct NMANAGER{
    struct NWORKER* workers;
    struct NJOB* jobs;
    
    pthread_cond_t jobs_cond;
    pthread_mutex_t jobs_mutex;
};

int nThreadPoolDestroy(nThreadPool* pool){

    struct NWORKER* woker = NULL;
    for (woker = pool->woker; woker != NULL; woker = woker->next) {
        woker->terminate = 1;
    }
    pthread_mutex_lock(&pool->jobs_mutex);
    pthread_cond_broadcast(pool->jobs_cond);
    pthread_mutex_unlock(&pool->jobs_mutex);
    
}

void nTHreadPoolPush(nThreadPool* pool,struct NJOB* job){
    
    pthread_mutex_lock(&pool->jobs_mutex);
    LL_ADD(job,pool->jobs);
    pthread_cond_signal(&pool->jobs_cond);
    
    pthread_mutex_unlock(&pool->jobs_mutex);
}

//0 -->1000
//task -->
int main() {
    std::cout << "Hello, World!" << std::endl;
    
    nThreadPool* pool;
    
    return 0;
}
